import json
from netMsgHandler import NetMsgHandler
from room import Room
from netMsgService import NetMsgService

class GameServer:
    def __init__(self) -> None:
        self.clients = set()
        self.clientDataDict = {}
        self.netMsgHandler = NetMsgHandler()
        self.netMsgService = NetMsgService()
        self.rooms = []
        self.globalRoomId = 1
        self.globalUserId = 1


    async def register(self, websocket):
        self.clients.add(websocket)
        print(f"Client {websocket.remote_address} connected.")

    
    async def unregister(self, websocket):
        user = self.getUser(websocket)
        if user != None:
            await self.netMsgService.userLeaveRoom(user, self)

        self.logout(websocket)
        self.clients.remove(websocket)
        print(f"Client {websocket.remote_address} disconnected. clientDataDict: ", self.clientDataDict)


    async def handleWebsocket(self, websocket, path):
        await self.register(websocket)

        try:
            while websocket.open:
                message = await websocket.recv()
                data = json.loads(message)
                methodName = data["msgType"] + "_handler"
                method2Call = getattr(self.netMsgHandler, methodName)
                await method2Call(data, websocket, self)
        except Exception as e:
            print(f"Error during WebSocket handling: {e}")
        finally:
            await self.unregister(websocket)


    def login(self, clientSocket, user):
        if clientSocket not in self.clientDataDict:
            self.clientDataDict[clientSocket] = user
            print(f"Client {clientSocket.remote_address} logged. clientDataDict: ", self.clientDataDict)

    
    def logout(self, clientSocket):
        if clientSocket in self.clientDataDict:
            del self.clientDataDict[clientSocket]

    
    async def sendMessage(self, msgType, data, clientSocket):
        if not clientSocket.open:
            return
        
        data["msgType"] = msgType
        await clientSocket.send(json.dumps(data))


    async def broadcastMessageRoomExcept(self, msgType, data, room, clientSocket):
        roomUsers = room.getUsers()
        sender = self.getUser(clientSocket)

        for user in roomUsers:
            if user != sender:
                await self.sendMessage(msgType, data, user.getClientSocket())

    
    async def broadcastMessageRoom(self, msgType, data, room):
        roomUsers = room.getUsers()

        for user in roomUsers:
            await self.sendMessage(msgType, data, user.getClientSocket())    


    async def broadcastMessage(self, msgType, data):
        for clientSocket in self.clientDataDict:
            await self.sendMessage(msgType, data, clientSocket)
                

    def getNextRoomId(self):
        nextRoomId = self.globalRoomId
        self.globalRoomId += 1
        return nextRoomId
    

    def getNextUserId(self):
        nextUserId = self.globalUserId
        self.globalUserId += 1
        return nextUserId
    

    def createRoom(self, roomDesc):
        room = Room(roomDesc, self)
        if room not in self.rooms:
            self.rooms.append(room)
        return room
        

    def destroyRoom(self, room):
        if room in self.rooms:
            self.rooms.remove(room)


    def userJoinRoom(self, user, room):
        room.userJoin(user)

    
    def getUser(self, clientSocket):
        if clientSocket in self.clientDataDict:
            return self.clientDataDict[clientSocket]
        return None
        

    def getRooms(self):
        return self.rooms
    

    def getRoomDTOs(self):
        rooms = self.getRooms()
        result = []
        for room in rooms:
            result.append(room.toDTO())
        return result
    

    def getRoomById(self, roomId):
        rooms = self.getRooms()
        for room in rooms:
            if room.roomId == roomId:
                return room
            
        return None



        